﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using GurLoader.GlobalHotkey;
using GurLoader.View;
using Moq;
using NUnit.Framework;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;

namespace GurLoaderWPF.Test.View
{
    [TestFixture]
    public class HotKeyTextBoxTests
    {
        [Test]
        [STAThread]
        public void CreateInstanceTest()
        {
            var box = new HotKeyTextBox();
            Assert.IsNotNull(box);
        }

        private class TestableHotKeyTextBox : HotKeyTextBox
        {
            public TestableHotKeyTextBox() : base()
            {
                
            }

            public TestableHotKeyTextBox(IKeyboard kbd) : base(kbd)
            {
                
            }

            public void CallOnShortcutKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
            {
                HotKeyTextBox.OnShortcutKeyPropertyChanged(d, args);
            }

            public void CallOnShortcutModifierKeyPropertyChanged(DependencyObject d,
                DependencyPropertyChangedEventArgs args)
            {
                HotKeyTextBox.OnShortcutModifierKeyPropertyChanged(d, args);
            }

            public void CallPreviewKeyDoen(KeyEventArgs e)
            {
                OnPreviewKeyDown(e);
            }
    
        }

        [Test]
        [STAThread]
        public void ShortcutKeyDependencyPropertyChangeTest()
        {
            var box = new TestableHotKeyTextBox();
            Assert.IsNotNull(box);

            Key testKey = Key.C;

            Key origKey = box.ShortcutKey;

            box.CallOnShortcutKeyPropertyChanged(box,
                new DependencyPropertyChangedEventArgs(HotKeyTextBox.ShortcutKeyProperty, box.ShortcutKey, testKey));

            Assert.AreEqual(testKey, box.ShortcutKey);
            Assert.AreNotEqual(origKey, box.ShortcutKey);
        }

        [Test]
        [STAThread]
        public void ShortcutModifierKeysDependencyPropertyChangeTest()
        {
            var box = new TestableHotKeyTextBox();
            Assert.IsNotNull(box);

            ModifierKeys testModifierKeys = ModifierKeys.Alt | ModifierKeys.Control;

            ModifierKeys origModifierKeys = box.ShortcutModifierKeys;

            box.CallOnShortcutModifierKeyPropertyChanged(box,
                new DependencyPropertyChangedEventArgs(HotKeyTextBox.ShortcutModifierKeysProperty, box.ShortcutModifierKeys, testModifierKeys));

            Assert.AreEqual(testModifierKeys, box.ShortcutModifierKeys);
            Assert.AreNotEqual(origModifierKeys, box.ShortcutModifierKeys);
        }

        private class FakeKeyboard : IKeyboard
        {
            public ModifierKeys Modifiers { get; set; }
        }

        [Test]
        [STAThread]
        public void StandardKeyAndModifiersTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            Assert.AreNotEqual(key, box.ShortcutKey);

            ModifierKeys modifierKeys = ModifierKeys.Shift;
            Assert.AreNotEqual(modifierKeys, box.ShortcutModifierKeys);
            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

        }

        [Test]
        [STAThread]
        public void TestStringNoModifersFTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.None;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual("F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestStringKeyPlusControlModifersTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.Control;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual("Ctrl+F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestStringKeyPlusShiftModifersTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.Shift;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual("Shift+F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestStringKeyPlusAltModifersTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.Alt;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual("Alt+F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestStringKeyPlusControlAndShiftModifersTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.Control | ModifierKeys.Shift;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual("Ctrl+Shift+F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestStringKeyPlusControlAndAltModifersTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.Control | ModifierKeys.Alt;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual("Ctrl+Alt+F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestStringKeyPlusShiftAndAltModifersTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.Shift | ModifierKeys.Alt;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual("Shift+Alt+F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestStringKeyPlusWindowsKeyTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.F;
            ModifierKeys modifierKeys = ModifierKeys.Windows;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            // Windows should have NO effect
            Assert.AreEqual("F", box.Text);
        }

        [Test]
        [STAThread]
        public void TestControlKeysCreateEmptyStringTest()
        {
            var kbd = new FakeKeyboard();

            var box = new TestableHotKeyTextBox(kbd);
            Assert.IsNotNull(box);

            Key key = Key.LeftAlt;
            ModifierKeys modifierKeys = ModifierKeys.Alt;

            kbd.Modifiers = modifierKeys;

            Mock<PresentationSource> mockPresentationSource = new Mock<PresentationSource>();

            box.CallPreviewKeyDoen(
                new KeyEventArgs(Keyboard.PrimaryDevice, mockPresentationSource.Object, 0, key)
                {
                    RoutedEvent = Keyboard.KeyDownEvent
                });

            Assert.AreEqual(key, box.ShortcutKey);
            Assert.AreEqual(modifierKeys, box.ShortcutModifierKeys);

            Assert.AreEqual(string.Empty, box.Text);
        }
    }
}
